using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;

namespace WIT.Global;

/// <summary>  
/// SqlHelperParameterCache提供缓存存储过程参数,并能够在运行时从存储过程中探索参数.  
/// </summary>  
public sealed class SqlHelperParameterCache
{
	private static Hashtable paramCache = Hashtable.Synchronized(new Hashtable());

	private SqlHelperParameterCache()
	{
	}

	/// <summary>  
	/// 探索运行时的存储过程,返回SqlParameter参数数组.  
	/// 初始化参数值为 DBNull.Value.  
	/// </summary>  
	/// <param>一个有效的数据库连接</param>  
	/// <param>存储过程名称</param>  
	/// <param>是否包含返回值参数</param>  
	/// <returns>返回SqlParameter参数数组</returns>  
	private static SqlParameter[] DiscoverSpParameterSet(SqlConnection connection, string spName, bool includeReturnValueParameter)
	{
		if (connection == null)
		{
			throw new ArgumentNullException("connection");
		}
		if (spName == null || spName.Length == 0)
		{
			throw new ArgumentNullException("spName");
		}
		SqlCommand sqlCommand = new SqlCommand(spName, connection);
		sqlCommand.CommandType = CommandType.StoredProcedure;
		connection.Open();
		SqlCommandBuilder.DeriveParameters(sqlCommand);
		connection.Close();
		if (!includeReturnValueParameter)
		{
			sqlCommand.Parameters.RemoveAt(0);
		}
		SqlParameter[] array = new SqlParameter[sqlCommand.Parameters.Count];
		sqlCommand.Parameters.CopyTo(array, 0);
		SqlParameter[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			array2[i].Value = DBNull.Value;
		}
		return array;
	}

	/// <summary>  
	/// SqlParameter参数数组的深层拷贝.  
	/// </summary>  
	/// <param>原始参数数组</param>  
	/// <returns>返回一个同样的参数数组</returns>  
	private static SqlParameter[] CloneParameters(SqlParameter[] originalParameters)
	{
		SqlParameter[] result = new SqlParameter[originalParameters.Length];
		int i = 0;
		for (int num = originalParameters.Length; i < num; i++)
		{
			result = (SqlParameter[])((ICloneable)originalParameters).Clone();
		}
		return result;
	}

	/// <summary>  
	/// 追加参数数组到缓存.  
	/// </summary>  
	/// <param>一个有效的数据库连接字符串</param>  
	/// <param>存储过程名或SQL语句</param>  
	/// <param>要缓存的参数数组</param>  
	public static void CacheParameterSet(string connectionString, string commandText, params SqlParameter[] commandParameters)
	{
		if (connectionString == null || connectionString.Length == 0)
		{
			throw new ArgumentNullException("connectionString");
		}
		if (commandText == null || commandText.Length == 0)
		{
			throw new ArgumentNullException("commandText");
		}
		string key = connectionString + ":" + commandText;
		paramCache[key] = commandParameters;
	}

	/// <summary>  
	/// 从缓存中获取参数数组.  
	/// </summary>  
	/// <param>一个有效的数据库连接字符</param>  
	/// <param>存储过程名或SQL语句</param>  
	/// <returns>参数数组</returns>  
	public static SqlParameter[] GetCachedParameterSet(string connectionString, string commandText)
	{
		if (connectionString == null || connectionString.Length == 0)
		{
			throw new ArgumentNullException("connectionString");
		}
		if (commandText == null || commandText.Length == 0)
		{
			throw new ArgumentNullException("commandText");
		}
		string key = connectionString + ":" + commandText;
		if (!(paramCache[key] is SqlParameter[] originalParameters))
		{
			return null;
		}
		return CloneParameters(originalParameters);
	}

	/// <summary>  
	/// 返回指定的存储过程的参数集  
	/// </summary>  
	/// <remarks>  
	/// 这个方法将查询数据库,并将信息存储到缓存.  
	/// </remarks>  
	/// <param>一个有效的数据库连接字符</param>  
	/// <param>存储过程名</param>  
	/// <returns>返回SqlParameter参数数组</returns>  
	public static SqlParameter[] GetSpParameterSet(string connectionString, string spName)
	{
		return GetSpParameterSet(connectionString, spName, includeReturnValueParameter: false);
	}

	/// <summary>  
	/// 返回指定的存储过程的参数集  
	/// </summary>  
	/// <remarks>  
	/// 这个方法将查询数据库,并将信息存储到缓存.  
	/// </remarks>  
	/// <param>一个有效的数据库连接字符.</param>  
	/// <param>存储过程名</param>  
	/// <param>是否包含返回值参数</param>  
	/// <returns>返回SqlParameter参数数组</returns>  
	public static SqlParameter[] GetSpParameterSet(string connectionString, string spName, bool includeReturnValueParameter)
	{
		if (connectionString == null || connectionString.Length == 0)
		{
			throw new ArgumentNullException("connectionString");
		}
		if (spName == null || spName.Length == 0)
		{
			throw new ArgumentNullException("spName");
		}
		using SqlConnection connection = new SqlConnection(connectionString);
		return GetSpParameterSetInternal(connection, spName, includeReturnValueParameter);
	}

	/// <summary>  
	/// [内部]返回指定的存储过程的参数集(使用连接对象).  
	/// </summary>  
	/// <remarks>  
	/// 这个方法将查询数据库,并将信息存储到缓存.  
	/// </remarks>  
	/// <param>一个有效的数据库连接字符</param>  
	/// <param>存储过程名</param>  
	/// <returns>返回SqlParameter参数数组</returns>  
	internal static SqlParameter[] GetSpParameterSet(SqlConnection connection, string spName)
	{
		return GetSpParameterSet(connection, spName, includeReturnValueParameter: false);
	}

	/// <summary>  
	/// [内部]返回指定的存储过程的参数集(使用连接对象)  
	/// </summary>  
	/// <remarks>  
	/// 这个方法将查询数据库,并将信息存储到缓存.  
	/// </remarks>  
	/// <param>一个有效的数据库连接对象</param>  
	/// <param>存储过程名</param>  
	/// <param>  
	/// 是否包含返回值参数  
	/// </param>  
	/// <returns>返回SqlParameter参数数组</returns>  
	internal static SqlParameter[] GetSpParameterSet(SqlConnection connection, string spName, bool includeReturnValueParameter)
	{
		if (connection == null)
		{
			throw new ArgumentNullException("connection");
		}
		using SqlConnection connection2 = (SqlConnection)((ICloneable)connection).Clone();
		return GetSpParameterSetInternal(connection2, spName, includeReturnValueParameter);
	}

	/// <summary>  
	/// [私有]返回指定的存储过程的参数集(使用连接对象)  
	/// </summary>  
	/// <param>一个有效的数据库连接对象</param>  
	/// <param>存储过程名</param>  
	/// <param>是否包含返回值参数</param>  
	/// <returns>返回SqlParameter参数数组</returns>  
	private static SqlParameter[] GetSpParameterSetInternal(SqlConnection connection, string spName, bool includeReturnValueParameter)
	{
		if (connection == null)
		{
			throw new ArgumentNullException("connection");
		}
		if (spName == null || spName.Length == 0)
		{
			throw new ArgumentNullException("spName");
		}
		string key = connection.ConnectionString + ":" + spName + (includeReturnValueParameter ? ":include ReturnValue Parameter" : "");
		SqlParameter[] array = paramCache[key] as SqlParameter[];
		if (array == null)
		{
			SqlParameter[] array2 = DiscoverSpParameterSet(connection, spName, includeReturnValueParameter);
			paramCache[key] = array2;
			array = array2;
		}
		return CloneParameters(array);
	}
}
